package nl.scalasim


import nl.scalasim.actors.Citizen
import scala.actors.Actor
import nl.scalasim.actors.traits.{SimulationActor, WorkplaceActor, HousingActor}
import java.io.{IOException, File}

/**
 * All messages that are sent between actors. 
 *
 * @author Yigal Duppen
 * @since Oct 1, 2010
 */
sealed class Message

/**
 * Generic message used to acknowledge the sender that the message
 * has been processed.  
 */
case object Ack extends Message

/**
 * Informs an actor with the StoppableActor trait that it must exit
 */
case object Stop extends Message

/**
 * Sent to all actors in the simulation on each tick. 
 */
case object Act extends Message

/**
 * Informs an actor that another actor has been added to the simulation
 * at the specified position
 */
case class ActorAdded(a: SimulationActor, pos: Position) extends Message

/**
 * Asks an actor if an actor with the specified descriptor and position
 * can be added to the simulation. 
 */
case class CanAdd(a: ActorDescriptor, pos: Position) extends Message

/**
 * Request from one simulation actor to another, asking it to perform its
 * job. 
 */
case object Process extends Message

/**
 * Response to a Process message by a ProductingActor.
 * @param goods the goods produced
 * @param amount the amount of goods produced during this specific call 
 */
case class Produced(goods: Goods, amount: Int) extends Message

/**
 * Connect an actor to another actor
 */
case class Connect(other: SimulationActor) extends Message


/**
 * Generic message indicating that c now lives at h
 */
case class LiveAt(c: SimulationActor, h: SimulationActor) extends Message

/**
 * Generic message indicating that c now works at w
 */
case class WorkAt(c: SimulationActor, w: SimulationActor) extends Message

/**
 * Generic response to indicate the number of available whatevers. 
 */
case class Available(amount: Int) extends Message

/**
 * Request from the governor to add citizens to the simulation. 
 */
case class AddCitizens(amount: Int) extends Message

/**
 * Request from a moving actor to move to a specific location
 */
case class MoveTo(a: SimulationActor, target: SimulationActor) extends Message

/**
 * Message to a citizen to indicate it has arrived
 */
case class Arrived(target: SimulationActor) extends Message

/**
 * Message from an actor to indicate it is looking for the closest
 * actor matching the predicate.
 */
case class FindClosest(a: SimulationActor, matches: SimulationActor => Boolean) extends Message

/**
 * Message from an actor to indicate it is looking for an actor that can provide
 * one of the goods in <code>goods</goods>. 
 */
case class FindGoods(a: SimulationActor, goods: List[(Goods, Int)]) extends Message

/**
 * Message to an actor to indicate the closest actor matching the predicate
 * in FindClosest.  
 */
case class Found(a: Option[SimulationActor]) extends Message

/** Advertising **/

case class Advertise(source: SimulationActor, available: Map[Goods, Amount]) extends Message


/** Storage messages **/

case class Store(goods: Goods, amount: Int) extends Message

case class Stored(goods: Goods, amount: Int) extends Message

case class Retrieve(goods: Goods, amount: Int) extends Message

case class Retrieved(goods: Goods, amount: Int) extends Message

/** Actor state messages **/

case object GetState extends Message

case class ActorState(descriptor: ActorDescriptor,
                      stored: Map[Goods, Amount],
                      maxCapacity: Int,
                      workers: Amount,
                      residents: Amount,
                      related: Set[SimulationActor]) extends Message

/** Level state messages **/

case class SaveGameState(f: File) extends Message

case class SaveGameStateResult(result: Either[IOException, Unit]) extends Message 